package logic

import (
	"common"
	"common/biz"
	"common/logs"
	"common/utils"
	"context"
	"core/models/entity"
	"core/repo"
	"core/service"
	"encoding/json"
	"fmt"
	"framework/msError"
	"framework/remote"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"hall/component/proto"
	"hall/models/response"
	"strconv"
	"sync"
	"time"
)

type VipManager struct {
	sync.RWMutex
	orderCh       chan *proto.VipBuy
	receiveCh     chan *proto.VipReceive
	signCh        chan *proto.SignReceive
	schedules     map[primitive.ObjectID]*time.Timer
	vipUsers      map[uint]*time.Timer
	userService   *service.UserService
	walletService *service.WalletService
	newsService   *service.NewsService
	manager       *Manager
	Session       map[uint]*remote.Session
}

func (m *VipManager) run() {
	//订单处理
	go m.chHandler()
	//重启任务，未支付订单自动退回
	logs.Warn("初始化重启定时任务-月卡-超时取消")
	go m.restartScheduleExecute()
	//启动vip用户每日扣除天数
	logs.Warn("初始化vip用户每日扣除天数")
	go m.restartScheduleVip()
}

func (m *VipManager) MonthlyCardOpen(ctx context.Context, uid uint, id uint, session *remote.Session) (*entity.VipOrder, *msError.Error) {
	role := m.userService.GetRoleInfo(ctx, uid)
	var err *msError.Error
	if role == nil || role.ID == 0 {
		logs.Error("[user]用户%d MonthlyCardOpen err:未获取到角色信息 req=%v", uid, role)
		return nil, biz.RequestDataError
	}
	if role.IsVIP {
		logs.Error("[user]用户%d MonthlyCardOpen err:该用户已经是vip，无需购买 req=%v", uid, role)
		return nil, biz.VipNotHave
	}
	vipInfo := m.userService.GetVip(ctx, id)
	if vipInfo == nil || vipInfo.ID == 0 {
		logs.Error("[user]用户%d Receive err:未获取到月卡信息 req=%v", uid, vipInfo)
		return nil, biz.RequestDataError
	}
	if vipInfo.Type == 1 {
		var order *entity.VipOrder
		order, err = m.CreateOrder(uid, id, session)
		return order, err
	} else {
		role, err = m.userService.MonthlyCardOpen(ctx, uid, id)
		if err != nil {
			return nil, err
		}
		go m.scheduleVip(uid, session)
		mongoUser, _ := m.userService.MongoGetUser(ctx, uid)
		m.manager.ServerMessagePush([]string{fmt.Sprintf("%d", uid)}, proto.UserNotifyData(mongoUser), session)
		return nil, nil
	}
}

func (m *VipManager) CreateOrder(uid, id uint, session *remote.Session) (*entity.VipOrder, *msError.Error) {
	//1.查询订单
	ctx := context.TODO()
	order := m.userService.VipOrderInfo(ctx, MaxOrderPay, uid, id)
	if order.OrderNo == "" {
		//2.无订单 查看月卡
		vip := m.userService.GetVip(ctx, id)
		if vip == nil || vip.ID == 0 {
			logs.Error("[Vip]用户%d Order err:未获取vip数据 req=%v", uid, vip)
			return nil, biz.RequestDataError
		}
		//3.查看用户是否有月卡
		role := m.userService.GetRoleInfo(ctx, uid)
		if role.IsVIP && role.VipTerm > 0 {
			logs.Error("[Vip]用户%d Order err:用户已有月卡 req=%v", uid, vip)
			return nil, biz.VipOrderExist
		}
		//4.向orderCh写入订单
		rule := new(proto.VipBuy)
		rule.VipOrder = &entity.VipOrder{
			UID:        uid,
			VipID:      id,
			OrderNo:    utils.GenOrderNumber("VIP"),
			VipName:    vip.Name,
			VipPrice:   vip.Price,
			VipTerm:    vip.Term,
			CreateTime: time.Now().Unix(),
		}
		rule.Session = session
		m.orderCh <- rule
	}
	return order, nil
}

func (m *VipManager) chHandler() {
	for {
		select {
		case data, ok := <-m.orderCh:
			if ok {
				//4.创建订单
				ctx := context.TODO()
				err := m.userService.VipCreateOrder(ctx, data.VipOrder)
				if err != nil {
					logs.Error("chHandler 创建订单失败,err:%v", err)
					continue
				}
				data.VipOrder = m.userService.VipOrderInfoByOrderNo(ctx, data.VipOrder.UID, data.VipOrder.OrderNo)
				go m.scheduleExecute(data.VipOrder, MaxOrderPayCancel, data.Session)
				//6.告诉用户订单已生成
				m.manager.ServerMessagePush([]string{strconv.Itoa(int(data.VipOrder.UID))}, proto.VipOrderNotifyData(data.VipOrder), data.Session)
			}
			break
		case res, ok := <-m.receiveCh:
			if ok {
				ctx := context.TODO()
				err := m.userService.VipReceive(ctx, res.VipReceive)
				if err != nil {
					logs.Error("chHandler 领取收益失败,err:%v", err)
					continue
				}
			}
			break
		case res, ok := <-m.signCh:
			if ok {
				ctx := context.TODO()
				err := m.userService.UserSignReceive(ctx, res.SignLog, res.VipReceive)
				if err != nil {
					var uidStr []string
					if res.SignLog != nil {
						uidStr = []string{fmt.Sprintf("%d", res.SignLog.UID)}
					} else {
						uidStr = []string{fmt.Sprintf("%d", res.VipReceive.UID)}
					}
					m.manager.ServerMessagePush(uidStr, proto.AbnormalNotifyData(common.F(err)), res.Session)
					continue
				}
			}
			break
		}
	}
}

func (m *VipManager) scheduleExecute(order *entity.VipOrder, times int64, session *remote.Session) {
	m.Lock()
	defer m.Unlock()
	// 触发定时
	timer, ok := m.schedules[order.Id]
	if ok {
		timer.Stop()
	}
	timer = time.AfterFunc(time.Second*time.Duration(times), func() {
		// 取消定时任务
		timer.Stop()
		delete(m.schedules, order.Id)
		orderData := order.OrderNo[3:11]
		hfResult, err := m.walletService.OrderQueryWallet(order.OrderNo, orderData)
		if err != nil {
			logs.Error("user VIP manager 自动取消,err=%v", err)
		}
		ctx := context.TODO()
		if hfResult.TransStat == "S" {
			order = m.userService.VipOrderInfoByOrderNo(ctx, order.UID, order.OrderNo)
			if order == nil || order.UID == 0 {
				logs.Error("user VIP manager 自动取消 订单不存在,err=%v", err)
				return
			}
			response, _ := json.Marshal(hfResult)
			err = m.userService.VipPay(ctx, order, string(response))
			if order == nil || order.UID == 0 {
				logs.Error("user VIP manager 自动取消 完成失败,err=%v", err)
				return
			}
			//添加月卡定时任务
			go m.scheduleVip(order.UID, session)
		} else {
			err = m.userService.VipOrderCancel(ctx, order)
			if err != nil {
				logs.Error("vip timer scheduleExecute,err=%v", err)
				return
			}
		}

	})
}

func (m *VipManager) OrderPay(uid uint, orderNo string) (string, *msError.Error) {
	//1.查询订单
	ctx := context.TODO()
	order := m.userService.VipOrderInfoByOrderNo(ctx, uid, orderNo)
	if order == nil || order.UID == 0 {
		logs.Error("[user]用户%d MonthlyCardPay err:订单不存在 req=%v", uid, order)
		return "", biz.GoodsOrderError
	}
	times := time.Now().Unix()
	if times > order.CreateTime+MaxOrderPay {
		logs.Error("[user]用户%d MonthlyCardPay OrderPay err:已超过操作时间，订单已取消 req=%v,订单时间%v,超时时间%v", uid, order, utils.TimeOrDateAsYear(times, "", "YmdHis"), utils.TimeOrDateAsYear(order.CreateTime+MaxOrderPay, "", "YmdHis"))
		return "", biz.GoodsOrderError
	}
	// TODO 调取支付,获取支付地址
	wallet := m.userService.GetWalletOfReal(ctx, uid)
	if wallet == nil || wallet.ID == 0 {
		logs.Error("[user]用户%d MonthlyCardPay OrderPay err:未获取到钱包数据 订单%v,req=%v", uid, order, wallet)
		return "", biz.WalletNotError
	}
	expTime := order.CreateTime + MaxOrderPay - time.Now().Unix()
	var resPay, err = m.walletService.VipPay(order.VipPrice, orderNo, wallet.UserCustID, wallet.IDCard, wallet.RealName.Name, wallet.RealName.IDCard, int(expTime))
	if err != nil {
		logs.Error("[user]用户%d MonthlyCardPay OrderPay err:调取支付失败 req=%v,payErr=%v", uid, order, err)
		return "", biz.NotPayError
	}
	return resPay, nil
}

func (m *VipManager) scheduleVip(uid uint, session *remote.Session) {
	m.Lock()
	defer m.Unlock()
	timer, ok := m.vipUsers[uid]
	if ok {
		timer.Stop()
	}
	t := time.Now()
	times := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 10, 0, time.Local).AddDate(0, 0, 1).Unix() - time.Now().Unix()
	//times = 10
	timer = time.AfterFunc(time.Second*time.Duration(times), func() {
		if session == nil {
			r, ok := m.Session[uid]
			if ok {
				session = r
			}
		}
		delete(m.vipUsers, uid)
		ctx := context.TODO()
		role := m.userService.GetRoleInfo(ctx, uid)
		if !role.IsVIP {
			timer.Stop()
			return
		}
		role.VipTerm--
		if role.VipTerm <= 0 {
			role.IsVIP = false
		}
		err := m.userService.UpdateRole(ctx, role)
		if err != nil {
			logs.Error("[user]用户%d scheduleVip err:更新角色失败 req=%v,err=%v", uid, role, err)
			timer.Reset(time.Second * time.Duration(1))
			return
		}
		if role.IsVIP {
			t = time.Now()
			times = time.Date(t.Year(), t.Month(), t.Day(), 0, 10, 0, 0, time.Local).AddDate(0, 0, 1).Unix() - time.Now().Unix()
			//times = 10
			timer.Reset(time.Second * time.Duration(times))
			if role.VipTerm <= 1 {
				//即将到期发送邮件
				content := fmt.Sprintf("你的会员将于%v到期，你需要到期后续费才能继续享受会员特权和服务", time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local).Format(time.DateTime))
				_ = m.newsService.AddNews(ctx, uid, "月卡到期提醒", content)
			}
		} else {
			timer.Stop()
			if session != nil {
				user, _ := m.userService.GetMongoUserInfo(ctx, uid)
				m.manager.ServerMessagePush([]string{strconv.Itoa(int(uid))}, proto.UserNotifyData(user), session)
			}
		}
	})
}

func (m *VipManager) restartScheduleExecute() {
	ctx := context.TODO()
	orders := m.userService.MongoVipOrderAll(ctx)
	for k, v := range *orders {
		data := v
		var times int64
		if time.Now().Unix() >= data.CreateTime+MaxOrderPayCancel {
			//已超时，未处理
			times = int64(k)
		} else {
			times = data.CreateTime + MaxOrderPayCancel - time.Now().Unix()
		}
		m.scheduleExecute(&data, times, nil)
	}
}

func (m *VipManager) restartScheduleVip() {
	ctx := context.TODO()
	roles := m.userService.RoleByVip(ctx)
	for _, v := range *roles {
		if v.IsVIP {
			m.scheduleVip(v.UID, nil)
		}
	}
}

func (m *VipManager) Receive(uid uint, id uint, session *remote.Session) *msError.Error {
	//查询本人身份
	ctx := context.TODO()
	role := m.userService.GetRoleInfo(ctx, uid)
	if role == nil || role.ID == 0 {
		logs.Error("[user]用户%d Receive err:未获取到角色信息 req=%v", uid, role)
		return biz.RequestDataError
	}
	if !role.IsVIP {
		logs.Error("[user]用户%d Receive err:请先购买月卡 req=%v", uid, role)
		return biz.VipNotHave
	}
	vip := m.userService.GetVip(ctx, id)
	if vip == nil || vip.ID == 0 {
		logs.Error("[user]用户%d Receive err:未获取到月卡信息 req=%v", uid, vip)
		return biz.RequestDataError
	}
	//查看本人今日是否领取
	t := time.Now()
	times := time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.Local)
	ymd := utils.TimeOrDateAsYear(0, "", "Y-m-d")
	receive := m.userService.GetVipReceiveCount(ctx, uid, id, ymd)
	if receive > 0 {
		logs.Error("[user]用户%d Receive err:今日已领取 req=%v", uid, vip)
		return biz.VipReceiveError
	}
	//向orderCh写入订单
	var vipReward []entity.VipReward
	for _, v := range vip.Reward {
		vipReward = append(vipReward, entity.VipReward{
			TypeID:     v.TypeID,
			TypeName:   v.Types.Name,
			TypeImg:    v.Types.Img,
			TypeModule: v.Types.Module,
			TypeType:   v.Types.Type,
			Num:        v.Num,
		})
	}
	rule := new(proto.VipReceive)
	rule.VipReceive = &entity.VipReceive{
		UID:         uid,
		VipID:       id,
		VipName:     vip.Name,
		VipReward:   vipReward,
		Dates:       ymd,
		ReceiveTime: times.Format(time.DateTime),
	}
	rule.Session = session
	m.receiveCh <- rule
	return nil
}

func (m *VipManager) SignReceive(ctx context.Context, uid uint, id uint, session *remote.Session) *msError.Error {
	data := m.userService.GetSign(ctx)
	round, cumulativeDay, dates := m.userService.LastSign(ctx, uid)
	role := m.userService.GetRoleInfo(ctx, uid)
	var info response.SignEach
	for _, v := range *data {
		isCan, isSign, isCondition, isVIPReceive := false, false, false, false
		if (v.Dates == 1 && dates == -1) || v.Dates == dates {
			isCan = true
		}
		userSignCount := m.userService.GetMongoUserSignInfo(ctx, uid, round, v.ID)
		//var userSignDates string
		if userSignCount != nil && userSignCount.UID != 0 {
			isSign = true
			//userSignDates = userSignCount.Dates
		}
		//if role.IsVIP {
		//	if isSign || isCan {
		//		if userSignDates == "" {
		//			userSignDates = utils.TimeOrDateAsYear(0, "", "Y-m-d")
		//		}
		//		vipCount := m.userService.GetVipReceiveCount(ctx, uid, id, userSignDates)
		//		if vipCount <= 0 {
		//			isVIPReceive = true
		//		}
		//	}
		//}
		if isSign {
			isCan = false
			isCondition = false
		}
		if isCan && dates != -1 {
			if role.IsVIP {
				isCondition = true
			} else {
				//TODO 查看今日是否玩过卡牌游戏
				gameCount := m.userService.GetMongoCardLogCount(ctx, uid)
				if gameCount > 0 && v.Dates == dates {
					isCondition = true
				}
			}
		}
		if dates == -1 && v.Dates == 1 {
			isCondition = true
		}
		if isSign {
			if !isVIPReceive {
				continue
			}
		} else {
			if !isCan || !isCondition {
				continue
			}
		}
		info = response.SignEach{
			SignID:       v.ID,
			SignDay:      v.Dates,
			TypeID:       v.TypeID,
			TypeImg:      v.Types.Img,
			TypeName:     v.Types.Name,
			Num:          v.Num,
			IsSign:       isSign,
			IsCan:        isCan,
			IsCondition:  isCondition,
			IsVIPReceive: isVIPReceive,
		}
	}
	if info.SignID == 0 {
		logs.Error("[userHandler]用户%d UserSign err:今日已签到或为满足签到条件 ", uid)
		return biz.SignOrNotConditionError
	}

	rule := new(proto.SignReceive)
	if !info.IsSign { //签到奖励
		UserSignLog := &entity.UserSignLog{
			UID:           uid,
			Round:         round,
			CumulativeDay: cumulativeDay + 1,
			SignID:        info.SignID,
			SignDay:       info.SignDay,
			TypeID:        info.TypeID,
			TypeName:      info.TypeName,
			TypeImg:       info.TypeImg,
			Num:           info.Num,
			Dates:         utils.TimeOrDateAsYear(0, "", "Y-m-d"),
			SignTime:      time.Now().Format(time.DateTime),
		}
		rule.SignLog = UserSignLog
	}
	//if info.IsVIPReceive { //月卡奖励
	//	vip := m.userService.GetVip(ctx, id)
	//	if vip == nil || vip.ID == 0 {
	//		logs.Error("[user]用户%d Receive err:未获取到月卡信息 req=%v", uid, vip)
	//		return biz.RequestDataError
	//	}
	//	//查看本人今日是否领取
	//	ymd := utils.TimeOrDateAsYear(0, "", "Y-m-d")
	//	receive := m.userService.GetVipReceiveCount(ctx, uid, id, ymd)
	//	if receive > 0 {
	//		logs.Error("[user]用户%d Receive err:今日已领取 req=%v", uid, vip)
	//		return biz.VipReceiveError
	//	}
	//	//向orderCh写入订单
	//	var vipReward []entity.VipReward
	//	for _, v := range vip.Reward {
	//		vipReward = append(vipReward, entity.VipReward{
	//			TypeID:     v.TypeID,
	//			TypeName:   v.Types.Name,
	//			TypeImg:    v.Types.Img,
	//			TypeModule: v.Types.Module,
	//			TypeType:   v.Types.Type,
	//			Num:        v.Num,
	//		})
	//	}
	//	rule.VipReceive = &entity.VipReceive{
	//		UID:         uid,
	//		VipID:       id,
	//		VipName:     vip.Name,
	//		VipReward:   vipReward,
	//		Dates:       ymd,
	//		ReceiveTime: time.Now().Format(time.DateTime),
	//	}
	//}
	rule.Session = session
	m.signCh <- rule
	return nil
}

func NewVipManager(r *repo.Manager) *VipManager {
	m := &VipManager{
		orderCh:       make(chan *proto.VipBuy, 1024),
		receiveCh:     make(chan *proto.VipReceive, 1024),
		signCh:        make(chan *proto.SignReceive, 1024),
		schedules:     make(map[primitive.ObjectID]*time.Timer),
		userService:   service.NewUserService(r),
		walletService: service.NewWalletService(r),
		newsService:   service.NewNewsService(r),
		manager:       NewManager(),
		Session:       make(map[uint]*remote.Session),
	}
	m.run()
	return m
}
